﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Reflection;
using PDO.DataPersistence.Core;
using PDO.DataPersistence.ServiceProvider;


namespace PDO.FX.App.DataExplorer
{
    public class DataExplorerPM :INotifyPropertyChanged
    {
        private System.Reflection.Assembly _pdoAssembly;

        public DataExplorerPM()
        {

            // Load datamodel assembly and create datbase connection if information is available.
            // If not, a settings dialog will be displayed by the UI.
            if (!string.IsNullOrEmpty(DataModelAssemblyFilePath))
            {
                LoadDataModelAssemblyFilePath(DataModelAssemblyFilePath);
            }

            if (!string.IsNullOrEmpty(DBConnectionString))
            {
                System.Data.SqlClient.SqlConnectionStringBuilder scb = new System.Data.SqlClient.SqlConnectionStringBuilder(DBConnectionString);
                IDataObjectSourceProvider dataProvider = new DataObjectSourceDirect(scb);
                DataSession.SetDataSourceProvider(dataProvider);
            }

        }

        public string DBConnectionString
        {
            get
            {
                return Properties.Settings.Default["DBConnectionString"].ToString();
            }
            set
            {
                Properties.Settings.Default["DBConnectionString"] = value;
                OnPropertyChanged("DBConnectionString");
            }

        }

        public string DataModelAssemblyFilePath
        {
            get
            {
                return Properties.Settings.Default["DataModelAssemblyFilePath"].ToString();
            }
            set
            {
                Properties.Settings.Default["DataModelAssemblyFilePath"] = value;
                OnPropertyChanged("DataModelAssemblyFilePath");

            }
        }

        
        public void LoadDataModelAssemblyFilePath(string afileName)
        {
            try
            {
                _pdoAssembly = System.Reflection.Assembly.LoadFile(afileName);

                _classInfoList = null;
                OnPropertyChanged("ClassInfoList");
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show("Error loading assembly.");
                return;
            }

            PersistableDataObject.RegisterAssembly(afileName);

        }


        private ObservableCollection<PersistableDataObjectClassInfo> _classInfoList;
        public ObservableCollection<PersistableDataObjectClassInfo> ClassInfoList
        {
            get
            {
                if (null == _classInfoList)
                {
                    try
                    {
                        _classInfoList = new ObservableCollection<PersistableDataObjectClassInfo>();

                        IEnumerable<Type> types = _pdoAssembly.GetTypes().OrderBy(cmp => cmp, new TypeComparer());
                        foreach (Type type in types)
                        {
                            if (type != null &&
                                type.BaseType != null &&
                                (type.BaseType.ToString() == typeof(PersistableDataObject).ToString()))
                            {
                                _classInfoList.Add(new PersistableDataObjectClassInfo(type));
                            }
                        }
                    }
                    catch (ReflectionTypeLoadException ex)
                    {
                        StringBuilder loaderExceptions = new StringBuilder("Loader Exceptions: ");
                        foreach (Exception lex in ex.LoaderExceptions)
                        {
                            loaderExceptions.AppendLine(lex.ToString());
                        }
                    }
                }

                return _classInfoList;
            }
        }


        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            // Property change events cross threading is handled by .Net - no special invokes reauired.
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }

    /// <summary>
    /// Comparer helper class
    /// </summary>
    public class TypeComparer : IComparer<Type>
    {
        public int Compare(Type d1, Type d2)
        {
            return string.Compare(d1.Name, d2.Name);
        }
    }

}
